/**
 * MCU 适配层 - 中断管理器
 */
#include <xil_io.h>
#include <xintc.h>
#include <FreeRTOS.h>

#include "mcu.h"

#if USE_FREERTOS
	// 注意：使用 FreeRTOS 的情况下，中断控制器被 FreeRTOS 接管了，要想使用中断控制器，只能引用 FreeRTOS 管理的中断控制器 !!!
	// - FreeRTOS 管理的中断控制器在 (libsrc)/freertos10_xilinx_v1_7/src/portZynqUltrascale.c 中定义为一个全局变量
	extern XIntc xInterruptControllerInstance;
#else
	#include "xparameters.h"
	// 注意：如果不使用 FreeRTOS，就需要在系统初始化时同样定义一个名为 xInterruptController 的中断控制器 !
	static XScuGic xInterruptController;
#endif

mcu_intc_t mcu_intc() {
	return &xInterruptControllerInstance;
}

std_err_t mcu_intc_init() {
	#if !USE_FREERTOS
		// 裸机开发时，需要自己管理中断控制器
		// 查找中断控制器对应的硬件配置信息
		XScuGic_Config *intc_cfg = XScuGic_LookupConfig(XPAR_SCUGIC_0_DEVICE_ID);
		if (NULL == intc_cfg) return STD_ERR_FAIL;

		// 初始化中断控制器
		err = XScuGic_CfgInitialize(&xInterruptController, intc_cfg, ScuGicConfigPtr->CpuBaseAddress);
		if(err != XST_SUCCESS) return STD_ERR_FAIL;

		// 设置并打开中断异常处理功能
		Xil_ExceptionInit();
		Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, &xInterruptController);
		Xil_ExceptionEnable();
	#endif // USE_FREERTOS
	return STD_ERR_OK;
}

std_err_t mcu_intc_set_priority_trigtype(mcu_intc_t intc, int32_t irqn, uint8_t priority, uint8_t trigtype) {
//	if(priority > 31) return STD_ERR_INVALID_ARG;
//	// 设置 GIC 中断触发类型
//	// !!! 注意：中断优先级低 3 位无效，只有 32 个优先级，取值范围为： 0, 8, 16, 32, 48, ..., 248
//	XScuGic_SetPriorityTriggerType((XScuGic*)intc, irqn, priority << 3, trigtype);
	return STD_ERR_OK;
}

std_err_t mcu_intc_get_priority_trigtype(mcu_intc_t intc, int32_t irqn, uint8_t *priority, uint8_t *trigtype) {
//	uint8_t priority0, trigtype0;
//	XScuGic_GetPriorityTriggerType((XScuGic*)intc, irqn, &priority0, &trigtype0);
//	if(priority) *priority = priority0;
//	if(trigtype) *trigtype = trigtype0;
	return STD_ERR_OK;
}

std_err_t mcu_intc_set_priority(mcu_intc_t intc, int32_t irqn, uint8_t priority) {
//	if(priority > 31) return STD_ERR_INVALID_ARG;
//	uint8_t priority0, trigtype;
//	XScuGic_GetPriorityTriggerType((XScuGic*)intc, irqn, &priority0, &trigtype);
//	XScuGic_SetPriorityTriggerType((XScuGic*)intc, irqn, priority << 3, trigtype);
	return STD_ERR_OK;
}

std_err_t mcu_intc_set_trigtype(mcu_intc_t intc, int32_t irqn, uint8_t trigtype) {
//	uint8_t priority, trigtype0;
//	XScuGic_GetPriorityTriggerType((XScuGic*)intc, irqn, &priority, &trigtype0);
//	XScuGic_SetPriorityTriggerType((XScuGic*)intc, irqn, priority, trigtype);
	return STD_ERR_OK;
}

std_err_t mcu_intc_register_handler(mcu_intc_t intc, int32_t irqn, mcu_isr_t isr, void *cookie) {
//	#if USE_FREERTOS
//		BaseType_t err = xPortInstallInterruptHandler(irqn, isr, cookie);
//		if (err != pdPASS) return STD_ERR_FAIL;
//	#else
//		s32 err = XScuGic_Connect((XScuGic*)intc, irqn, isr, cookie);
//		if (err != XST_SUCCESS) return STD_ERR_FAIL;
//	#endif
	return STD_ERR_OK;
}

std_err_t mcu_intc_enable(mcu_intc_t intc, int32_t irqn, bool enable) {
//	#if USE_FREERTOS
//		if(enable) {
//			vPortEnableInterrupt(irqn);
//		} else {
//			vPortDisableInterrupt(irqn);
//		}
//	#else
//		if(enable) {
//			XScuGic_Enable((XScuGic*)intc, irqn);
//		} else {
//			XScuGic_Disable((XScuGic*)intc, irqn);
//		}
//	#endif
	return STD_ERR_OK;
}
